package com.atguigu.gmall.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.gmall.common.constant.MqConst;
import com.atguigu.gmall.common.service.RabbitService;
import com.atguigu.gmall.common.util.HttpClientUtil;
import com.atguigu.gmall.model.enums.OrderStatus;
import com.atguigu.gmall.model.enums.ProcessStatus;
import com.atguigu.gmall.model.order.OrderDetail;
import com.atguigu.gmall.model.order.OrderInfo;
import com.atguigu.gmall.order.mapper.OrderDetailMapper;
import com.atguigu.gmall.order.mapper.OrderInfoMapper;
import com.atguigu.gmall.order.service.OrderService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Array;
import java.util.*;

/**
 * @author mqx
 * @date 2020-12-18 09:36:14
 */
@Service
public class OrderServiceImpl extends ServiceImpl<OrderInfoMapper,OrderInfo> implements OrderService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private OrderDetailMapper orderDetailMapper;

    @Autowired
    private RabbitService rabbitService;

    @Override
    @Transactional
    public Long saveOrder(OrderInfo orderInfo) {

        //  总金额，订单状态，userId,out_trade_no 第三方交易编号，订单描述，创建时间，过期时间，进程状态
        orderInfo.sumTotalAmount();
        orderInfo.setOrderStatus(OrderStatus.UNPAID.name());
        //  orderInfo.setUserId();//    userId 在控制器获取
        String outTradeNo = "ATGUIGU" + System.currentTimeMillis() + "" + new Random().nextInt(1000);; //第三方交易编号 这个编号不能重复
        orderInfo.setOutTradeNo(outTradeNo);
        //  订单描述 {获取每个商品的名称}
        //        StringBuilder sb = new StringBuilder();
        //        for (OrderDetail orderDetail : orderInfo.getOrderDetailList()) {
        //            //  拼接字符串
        //            sb.append(orderDetail.getSkuName());
        //        }
        //        if (sb.length()>200){
        //            //  包前不包后。
        //            orderInfo.setTradeBody(sb.toString().substring(0,200));
        //        }else {
        //            orderInfo.setTradeBody(sb.toString());
        //        }

        orderInfo.setTradeBody("购买笔记本...");

        orderInfo.setCreateTime(new Date());
        //  过期时间默认24小时
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE,1);
        orderInfo.setExpireTime(calendar.getTime());

        //  进程状态
        orderInfo.setProcessStatus(ProcessStatus.UNPAID.name());
        //  保存订单
        orderInfoMapper.insert(orderInfo);
        //  保存订单明细
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();

        for (OrderDetail orderDetail : orderDetailList) {
            orderDetail.setOrderId(orderInfo.getId());
            orderDetailMapper.insert(orderDetail);
        }

        //  返回订单Id
        return orderInfo.getId();
    }

    @Override
    public String getTradeNo(String userId) {
        //  声明流水号
        String tradeNo = UUID.randomUUID().toString();
        //  放入缓存
        String tradeNoKey = "tradeCode:"+userId;

        redisTemplate.opsForValue().set(tradeNoKey,tradeNo);

        //  返回
        return tradeNo;
    }

    @Override
    public boolean checkTradeNo(String tradeNo, String userId) {
        //  先获取缓存的
        String tradeNoKey = "tradeCode:"+userId;
        String tradeNoRedis = (String) redisTemplate.opsForValue().get(tradeNoKey);
        //  比较返回结果
        return tradeNo.equals(tradeNoRedis);
    }

    @Override
    public void deleteTradeNo(String userId) {
        //  定义缓存的key
        String tradeNoKey = "tradeCode:"+userId;
        //  执行删除
        redisTemplate.delete(tradeNoKey);
    }

    @Override
    public boolean checkStock(Long skuId, Integer skuNum) {
        //  远程调用：
        //  http://localhost:9001/hasStock?skuId=10221&num=2
        //  0：无库存   1：有库存
        String res = HttpClientUtil.doGet("http://localhost:9001/hasStock?skuId=" + skuId + "&num=" + skuNum);
        //  判断返回结果
        return "1".equals(res);
    }

    @Override
    public void execExpiredOrder(Long orderId) {
        //    update order_info set order_status= ? process_status=? where id = ?;
        //        OrderInfo orderInfo = new OrderInfo();
        //        orderInfo.setId(orderId);
        //        orderInfo.setOrderStatus(OrderStatus.CLOSED.name());
        //        orderInfo.setProcessStatus(ProcessStatus.CLOSED.name());
        //        orderInfoMapper.updateById(orderInfo);

        //  进度中能够获取到订单状态
        //  后续会有很多地方，都会使用到根据进度状态来更新订单。
        updateOrderStatus(orderId,ProcessStatus.CLOSED);

        //  发送一个消息关闭电商本地paymentInfo 交易记录
        rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_PAYMENT_CLOSE,MqConst.ROUTING_PAYMENT_CLOSE,orderId);


    }

    public void updateOrderStatus(Long orderId, ProcessStatus processStatus) {
        //  update order_info set order_status= ? process_status=? where id = ?;
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setId(orderId);
        orderInfo.setOrderStatus(processStatus.getOrderStatus().name());
        orderInfo.setProcessStatus(processStatus.name());
        orderInfoMapper.updateById(orderInfo);
    }

    @Override
    public OrderInfo getOrderInfo(Long orderId) {
        //  select * from order_info where id = orderId;
        //  查询订单明细
        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
        //  select * from order_detail where order_id = orderId;
        if (orderInfo!=null){

            orderInfo.setOrderDetailList(orderDetailMapper.selectList(new QueryWrapper<OrderDetail>().eq("order_id",orderId)));
        }
        return orderInfo;
    }

    @Override
    public void sendOrderStatus(Long orderId) {
        //  改变一下订单的状态
        updateOrderStatus(orderId,ProcessStatus.NOTIFIED_WARE);

        //  先获取到发送消息的数据，由OrderInfo 组成。
        //  需要获取订单对象
        OrderInfo orderInfo = getOrderInfo(orderId);
        //  在类中定义一个方法，将orderInfo 转换为Map
        Map map = this.initWareOrder(orderInfo);
        //  将map 转换为Json
        String wareJson = JSON.toJSONString(map);

        //  发送消息
        rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_WARE_STOCK,MqConst.ROUTING_WARE_STOCK,wareJson);
    }
    //  在类中定义一个方法，将orderInfo 转换为Map
    //  后面拆单需要使用
    public Map initWareOrder(OrderInfo orderInfo) {
        HashMap<String, Object> map = new HashMap<>();

        map.put("orderId",orderInfo.getId());
        map.put("consignee", orderInfo.getConsignee());
        map.put("consigneeTel", orderInfo.getConsigneeTel());
        map.put("orderComment", orderInfo.getOrderComment());
        map.put("orderBody", orderInfo.getTradeBody());
        map.put("deliveryAddress", orderInfo.getDeliveryAddress());
        map.put("paymentWay", "2");
        map.put("wareId", orderInfo.getWareId());// 仓库Id ，减库存拆单时需要使用！
        //  存储的数据是订单明细
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        //  声明一个List集合来存储map
        List<Map> maps = new ArrayList<>();

        //  details:[{skuId:101,skuNum:1,skuName:’小米手64G’},{skuId:201,skuNum:1,skuName:’索尼耳机’}]
        for (OrderDetail orderDetail : orderDetailList) {
            HashMap<String, Object> detailMap = new HashMap<>();
            detailMap.put("skuId", orderDetail.getSkuId());
            detailMap.put("skuNum", orderDetail.getSkuNum());
            detailMap.put("skuName", orderDetail.getSkuName());
            maps.add(detailMap);
        }
        //  存储订单明细
        map.put("details",maps);
        return map;
    }

    @Override
    public List<OrderInfo> orderSplit(String orderId, String wareSkuMap) {
        /*
        1.  先获取原始订单
        2.  将wareSkuMap 变为我们能操作的对象 [{"wareId":"1","skuIds":["2","10"]},{"wareId":"2","skuIds":["3"]}]
        3.  给子订单进行赋值，并子订单添加到集合中
        4.  保存子订单
        5.  更新原始订单的状态
         */
        List<OrderInfo> orderInfoList = new ArrayList<>();
        OrderInfo orderInfoOrigin = this.getOrderInfo(Long.parseLong(orderId));
        //  将wareSkuMap 变为我们能操作的对象
        //  [{"wareId":"1","skuIds":["2","10"]},{"wareId":"2","skuIds":["3"]}]
        //  List<Map>
        List<Map> mapList = JSON.parseArray(wareSkuMap, Map.class);
        //  判断集合
        if (!CollectionUtils.isEmpty(mapList)){
            for (Map map : mapList) {
                //  获取仓库Id
                String wareId = (String) map.get("wareId");
                //  获取仓库对应的商品Id
                List<String> skuIdList = (List<String>) map.get("skuIds");
                //  创建一个子订单,赋值
                OrderInfo subOrderInfo = new OrderInfo();
                BeanUtils.copyProperties(orderInfoOrigin,subOrderInfo);
                //  设置主键为null
                subOrderInfo.setId(null);
                //  设置某些字段
                subOrderInfo.setWareId(wareId);
                subOrderInfo.setParentOrderId(Long.parseLong(orderId));

                //  计算价格,必须给子订单的订单明细
                //  根据skuId 获取子订单明细
                //  先获取到原始订单明细
                List<OrderDetail> orderDetailList = orderInfoOrigin.getOrderDetailList();

                //  声明一个子订单明细集合
                List<OrderDetail> orderDetails = new ArrayList<>();
                //  遍历原始订单明细
                for (OrderDetail orderDetail : orderDetailList) {
                    //  找到仓库对应的skuIdList
                    for (String skuId : skuIdList) {
                        //  根据skuId
                        //                        if (orderDetail.getSkuId().compareTo(Long.parseLong(skuId))==0){
                        //
                        //                        }
                        if (orderDetail.getSkuId()==Long.parseLong(skuId)){
                            //  将子订单明细对象放入子订单中
                            orderDetails.add(orderDetail);
                        }
                    }
                }
                subOrderInfo.setOrderDetailList(orderDetails);
                subOrderInfo.sumTotalAmount();
                //  保存子订单
                this.saveOrder(subOrderInfo);

                //  将子订单添加到集合中
                orderInfoList.add(subOrderInfo);
            }
        }
        //  修改原始订单状态
        this.updateOrderStatus(Long.parseLong(orderId),ProcessStatus.SPLIT);
        return orderInfoList;
    }

    @Override
    public void execExpiredOrder(Long orderId, String flag) {
        //  进度中能够获取到订单状态
        //  后续会有很多地方，都会使用到根据进度状态来更新订单。
        updateOrderStatus(orderId,ProcessStatus.CLOSED);
        if ("2".equals(flag)){
            //  发送一个消息关闭电商本地paymentInfo 交易记录
            rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_PAYMENT_CLOSE,MqConst.ROUTING_PAYMENT_CLOSE,orderId);

        }

    }
}
